package org.sun.consumer;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.sun.consumer.feign.ProducerInterface;

@RestController
@Slf4j
public class ConsumerController {
    Logger logger= org.slf4j.LoggerFactory.getLogger(ConsumerController.class);
    private final LoadBalancerClient loadBalancerClient;
    private final RestTemplate restTemplate;
    private final ProducerInterface producerInterface;

    @Value("${spring.application.name}")
    private String appName;

    @Autowired
    public ConsumerController(LoadBalancerClient loadBalancerClient,
                              RestTemplate restTemplate,
                              ProducerInterface producerInterface){
        this.restTemplate=restTemplate;
        this.loadBalancerClient=loadBalancerClient;
        this.producerInterface=producerInterface;
    }

    //loadbalance
    @GetMapping("/echo/app-name")
    public String echoAppName(){
        log.info("echo app name ");
        logger.info("echo app name!");
        //Access through the combination of LoadBalanceClient and RestTemplate
        ServiceInstance serviceInstance = loadBalancerClient.choose("sunshine");
        String path = String.format("http://%s:%s/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName);
        System.out.println("request path:" +path);
        return restTemplate.getForObject(path,String.class);

    }

    //客户端负载均衡调试。 https://blog.csdn.net/cdy1996/article/details/103456675
    @GetMapping("/echo/blc")
    public String testLoadbalance(){
        String inventoryServiceUrl = "http://sunshine/echo/1";
        String stockAvailable = restTemplate.getForObject(inventoryServiceUrl, String.class);
        return stockAvailable;
    }


    /**
     * fallback 针对的是所有的异常  blockhandler 针对的是限流降级的异常
     * https://sentinelguard.io/zh-cn/docs/annotation-support.html
     * @param some
     * @return
     * @throws Exception
     */
    @GetMapping("/sentinel/action/{some}")
    @SentinelResource(value = "sentinelAction",fallback = "sentinelActionFallback",blockHandler = "blockHandler")
    public String sentinelAction(@PathVariable("some") String some) throws Exception {
        if("1".equals(some)){
            throw new Exception("some exception");
        }
        return some;
    }

    /**
     * cd /Users/yushengjun/IdeaProjects/Sentinel/sentinel-dashboard/target
     * java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8084 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
     *
     * blockHandler / blockHandlerClass: blockHandler 对应处理 BlockException 的函数名称，可选项。blockHandler
     * 函数访问范围需要是 public，返回类型需要与原方法相匹配，参数类型需要和原方法相匹配并且最后加一个额外的参数，
     * 类型为 BlockException。blockHandler 函数默认需要和原方法在同一个类中。
     *
     *
     * 若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象，注意对应的函数必需为 static 函数，否则无法解析。
     * @return
     */
    public String blockHandler(String some, BlockException e){
        return "block";
    }

    /**
     * 返回值类型必须与原函数返回值类型一致；
     * 方法参数列表需要和原函数一致，或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
     * fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数，则可以指定 fallbackClass 为对应的类的 Class 对象，注意对应的函数必需为 static 函数，否则无法解析。
     * @param some
     * @return
     */
    public String sentinelActionFallback(String some,Throwable throwable){
        logger.info("sentinelActionFallback");
        return "sentinelActionFallback";
    }


    ///Users/yushengjun/IdeaProjects/Sentinel/sentinel-dashboard/target/sentinel-dashboard.jar
    //feign client
    @GetMapping("/echo2/app-name-openfeign")
    public String echoAppNameByFeign(String appName){
        return producerInterface.echo2(appName);
    }

    @GetMapping("/echo/app-name-openfeign")
    public String echoAppNameByFeign1(String appName){
        return producerInterface.echo(appName);
    }



}
